<template>
  <div
    :class="[{ 'fullscreen': s_fullScreen, 'shadow': boxShadow }]"
    class="v-note-wrapper markdown-body"
    :style="{'box-shadow': boxShadow ? boxShadowStyle : ''}"
  >
    <!--工具栏-->
    <div
      class="v-note-op"
      v-show="toolbarsFlag"
      :style="{'background': toolbarsBackground}"
    >
      <v-md-toolbar-left
        ref="toolbar_left"
        :editable="editable"
        :transition="transition"
        @toolbar_left_click="toolbar_left_click"
        @toolbar_left_addlink="toolbar_left_addlink"
        :toolbars="toolbars"
        @imgAdd="$imgAdd"
        @imgDel="$imgDel"
        @imgTouch="$imgTouch"
        :image_filter="imageFilter"
        :class="{'transition': transition}"
      >
        <slot
          name="left-toolbar-before"
          slot="left-toolbar-before"
        />
        <slot
          name="left-toolbar-after"
          slot="left-toolbar-after"
        />
      </v-md-toolbar-left>
      <v-md-toolbar-right
        ref="toolbar_right"
        @toolbar_right_click="toolbar_right_click"
        :toolbars="toolbars"
        :s_subfield="s_subfield"
        :s_preview_switch="s_preview_switch"
        :s_fullScreen="s_fullScreen"
        :s_html_code="s_html_code"
        :s_navigation="s_navigation"
        :class="{'transition': transition}"
      >
        <slot
          name="right-toolbar-before"
          slot="right-toolbar-before"
        />
        <slot
          name="right-toolbar-after"
          slot="right-toolbar-after"
        />
      </v-md-toolbar-right>
    </div>
    <!--编辑展示区域-->
    <div class="v-note-panel">
      <!--编辑区-->
      <div
        ref="vNoteEdit"
        @scroll="$v_edit_scroll"
        class="v-note-edit divarea-wrapper"
        :class="{'scroll-style': s_scrollStyle, 'scroll-style-border-radius': s_scrollStyle && !s_preview_switch && !s_html_code, 'single-edit': !s_preview_switch && !s_html_code, 'single-show': (!s_subfield && s_preview_switch) || (!s_subfield && s_html_code), 'transition': transition}"
        @click="textAreaFocus"
      >
        <div
          class="content-input-wrapper"
          :style="{'background-color': editorBackground}"
        >
          <!-- 双栏 -->
          <v-autoTextarea
            ref="vNoteTextarea"
            :placeholder="placeholder ? placeholder : '开始编辑...'"
            class="content-input"
            :fontSize="fontSize"
            lineHeight="1.5"
            v-model="d_value"
            fullHeight
            :style="{'background-color': editorBackground}"
          ></v-autoTextarea>
        </div>
      </div>
      <!--展示区-->
      <div
        :class="{'single-show': (!s_subfield && s_preview_switch) || (!s_subfield && s_html_code)}"
        v-show="s_preview_switch || s_html_code"
        class="v-note-show"
      >
        <div
          ref="vShowContent"
          v-html="d_render"
          v-show="!s_html_code"
          :class="{'scroll-style': s_scrollStyle, 'scroll-style-border-radius': s_scrollStyle}"
          class="v-show-content"
          :style="{'background-color': previewBackground}"
        >
        </div>
        <div
          v-show="s_html_code"
          :class="{'scroll-style': s_scrollStyle, 'scroll-style-border-radius': s_scrollStyle}"
          class="v-show-content-html"
          :style="{'background-color': previewBackground}"
        >
          {{d_render}}
        </div>
      </div>

      <!--标题导航-->
      <transition name="slideTop">
        <div
          v-show="s_navigation"
          class="v-note-navigation-wrapper"
          :class="{'transition': transition}"
        >
          <div class="v-note-navigation-title">
            导航目录<i
              @click="toolbar_right_click('navigation')"
              class="fa fa-halo-times v-note-navigation-close"
              aria-hidden="true"
            ></i>
          </div>
          <div
            ref="navigationContent"
            class="v-note-navigation-content"
            :class="{'scroll-style': s_scrollStyle}"
          >
          </div>
        </div>
      </transition>

    </div>
    <!-- 预览图片 -->
    <transition name="fade">
      <div
        @click="d_preview_imgsrc=null"
        class="v-note-img-wrapper"
        v-if="d_preview_imgsrc"
      >
        <img
          :src="d_preview_imgsrc"
          alt="none"
        >
      </div>
    </transition>
    <!--阅读模式-->
    <div
      :class="{'show': s_readmodel}"
      class="v-note-read-model scroll-style"
      ref="vReadModel"
    >
      <div
        ref="vNoteReadContent"
        class="v-note-read-content"
        v-html="d_render"
      >
      </div>
    </div>
  </div>
</template>

<script>
import { autoTextarea } from "auto-textarea";
import { keydownListen } from "./lib/core/keydown-listen.js";
import hljsCss from "./lib/core/hljs/lang.hljs.css.js";
import hljsLangs from "./lib/core/hljs/lang.hljs.js";
import {
  fullscreenchange,
  /* windowResize, */
  scrollLink,
  insertTextAtCaret,
  getNavigation,
  insertTab,
  unInsertTab,
  insertOl,
  insertUl,
  insertEnter,
  removeLine,
  loadLink,
  loadScript,
  ImagePreviewListener
} from "./lib/core/extra-function.js";
import { p_ObjectCopy_DEEP, stopEvent } from "./lib/util.js";
import {
  toolbar_left_click,
  toolbar_left_addlink
} from "./lib/toolbar_left_click.js";
import { toolbar_right_click } from "./lib/toolbar_right_click.js";
import { CONFIG } from "./lib/config.js";
import hljs from "./lib/core/highlight.js";
import markdown from "./lib/mixins/markdown.js";

import md_toolbar_left from "./components/md-toolbar-left.vue";
import md_toolbar_right from "./components/md-toolbar-right.vue";
import "./lib/font/css/fontello.css";
export default {
  mixins: [markdown],
  props: {
    scrollStyle: {
      // 是否渲染滚动条样式(webkit)
      type: Boolean,
      default: true
    },
    boxShadow: {
      // 是否添加阴影
      type: Boolean,
      default: true
    },
    transition: {
      // 是否开启动画过渡
      type: Boolean,
      default: true
    },
    autofocus: {
      // 是否自动获取焦点
      type: Boolean,
      default: true
    },
    fontSize: {
      // 字体大小
      type: String,
      default: "15px"
    },
    toolbarsBackground: {
      // 工具栏背景色
      type: String,
      default: "#ffffff"
    },
    editorBackground: {
      // TODO: 编辑栏背景色
      type: String,
      default: "#ffffff"
    },
    previewBackground: {
      // 预览栏背景色
      type: String,
      default: "#fbfbfb"
    },
    boxShadowStyle: {
      // 阴影样式
      type: String,
      default: "0 2px 12px 0 rgba(0, 0, 0, 0.1)"
    },
    value: {
      // 初始 value
      type: String,
      default: ""
    },
    subfield: {
      type: Boolean,
      default: true
    },
    navigation: {
      type: Boolean,
      default: false
    },
    defaultOpen: {
      type: String,
      default: null
    },
    editable: {
      // 是否开启编辑
      type: Boolean,
      default: true
    },
    toolbarsFlag: {
      // 是否开启工具栏
      type: Boolean,
      default: true
    },
    toolbars: {
      // 工具栏
      type: Object,
      default() {
        return CONFIG.toolbars;
      }
    },
    codeStyle: {
      // <code></code> 样式
      type: String,
      default() {
        return "github";
      }
    },
    placeholder: {
      // 编辑器默认内容
      type: String,
      default: null
    },
    ishljs: {
      type: Boolean,
      default: true
    },
    externalLink: {
      type: [Object, Boolean],
      default: true
    },
    imageFilter: {
      type: Function,
      default: null
    },
    imageClick: {
      type: Function,
      default: null
    },
    tabSize: {
      type: Number,
      default: 0
    },
    shortCut: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      s_right_click_menu_show: false,
      right_click_menu_top: 0,
      right_click_menu_left: 0,
      s_subfield: (() => {
        return this.subfield;
      })(),
      s_autofocus: true,
      // 标题导航
      s_navigation: (() => {
        return this.navigation;
      })(),
      s_scrollStyle: (() => {
        return this.scrollStyle;
      })(), // props 是否渲染滚动条样式
      d_value: "", // props 文本内容
      d_render: "", // props 文本内容render
      s_preview_switch: (() => {
        let default_open_ = this.defaultOpen;
        if (!default_open_) {
          default_open_ = this.subfield ? "preview" : "edit";
        }
        return default_open_ === "preview" ? true : false;
      })(), // props true 展示编辑 false展示预览
      s_fullScreen: false, // 全屏编辑标志
      s_html_code: false, // 分栏情况下查看html
      edit_scroll_height: -1,
      s_readmodel: false,
      s_table_enter: false, // 回车事件是否在表格中执行
      d_history: (() => {
        let temp_array = [];
        temp_array.push(this.value);
        return temp_array;
      })(), // 编辑记录
      d_history_index: 0, // 编辑记录索引
      currentTimeout: "",
      d_image_file: [],
      d_preview_imgsrc: null, // 图片预览地址
      s_external_link: {
        markdown_css: function() {
          return "//cdn.jsdelivr.net/npm/github-markdown-css@3.0.1/github-markdown.min.css";
        },
        hljs_js: function() {
          return "//cdn.jsdelivr.net/npm/highlight.js@9.12.0/lib/highlight.min.js";
        },
        hljs_lang: function(lang) {
          return (
            "//cdn.jsdelivr.net/npm/highlight.js@9.12.0/lib/languages/" +
            lang +
            ".min.js"
          );
        },
        hljs_css: function(css) {
          if (hljsCss[css]) {
            return (
              "//cdn.jsdelivr.net/npm/highlight.js@9.12.0/styles/" +
              css +
              ".min.css"
            );
          }
          return "";
        },
        katex_js: function() {
          return "//cdn.jsdelivr.net/npm/katex@0.8.3/dist/katex.min.js";
        },
        katex_css: function() {
          return "//cdn.jsdelivr.net/npm/katex@0.8.3/dist/katex.min.css";
        }
      },
      p_external_link: {}
    };
  },
  created() {
    var $vm = this;
    this.initExternalFuc();
    this.$nextTick(() => {
      // 初始化Textarea编辑开关
      $vm.editableTextarea();
    });
  },
  mounted() {
    var $vm = this;
    this.$el.addEventListener("paste", function(e) {
      $vm.$paste(e);
    });
    this.$el.addEventListener("drop", function(e) {
      $vm.$drag(e);
    });
    // 浏览器siz大小
    /* windowResize(this); */
    keydownListen(this);
    // 图片预览事件监听
    ImagePreviewListener(this);
    // 设置默认焦点
    if (this.autofocus) {
      this.getTextareaDom().focus();
    }
    // fullscreen事件
    fullscreenchange(this);
    this.d_value = this.value;
    this.loadExternalLink("markdown_css", "css");
    this.loadExternalLink("katex_css", "css");
    this.loadExternalLink("katex_js", "js", function() {
      $vm.iRender(true);
    });
    this.loadExternalLink("hljs_js", "js", function() {
      $vm.iRender(true);
    });

    if (
      !(
        typeof $vm.externalLink === "object" &&
        typeof $vm.externalLink["markdown_css"] === "function"
      )
    ) {
      // 没有外部文件要来接管markdown样式，可以更改markdown样式。
      $vm.codeStyleChange($vm.codeStyle, true);
    }
  },
  getMarkdownIt() {
    return this.mixins[0].data().markdownIt;
  },
  methods: {
    loadExternalLink(name, type, callback) {
      if (typeof this.p_external_link[name] !== "function") {
        if (this.p_external_link[name] != false) {
          console.error(
            "external_link." + name,
            "is not a function, if you want to disabled this error log, set external_link." +
              name,
            "to function or false"
          );
        }
        return;
      }
      var _obj = {
        css: loadLink,
        js: loadScript
      };
      if (_obj.hasOwnProperty(type)) {
        _obj[type](this.p_external_link[name](), callback);
      }
    },
    initExternalFuc() {
      var $vm = this;
      var _external_ = [
        "markdown_css",
        "hljs_js",
        "hljs_css",
        "hljs_lang",
        "katex_js",
        "katex_css"
      ];
      var _type_ = typeof $vm.externalLink;
      var _is_object = _type_ === "object";
      var _is_boolean = _type_ === "boolean";
      for (var i = 0; i < _external_.length; i++) {
        if (
          (_is_boolean && !$vm.externalLink) ||
          (_is_object && $vm.externalLink[_external_[i]] === false)
        ) {
          $vm.p_external_link[_external_[i]] = false;
        } else if (
          _is_object &&
          typeof $vm.externalLink[_external_[i]] === "function"
        ) {
          $vm.p_external_link[_external_[i]] = $vm.externalLink[_external_[i]];
        } else {
          $vm.p_external_link[_external_[i]] =
            $vm.s_external_link[_external_[i]];
        }
      }
    },
    textAreaFocus() {
      this.$refs.vNoteTextarea.$refs.vTextarea.focus();
    },
    $drag($e) {
      var dataTransfer = $e.dataTransfer;
      if (dataTransfer) {
        var files = dataTransfer.files;
        if (files.length > 0) {
          $e.preventDefault();
          this.$refs.toolbar_left.$imgFilesAdd(files);
        }
      }
    },
    $paste($e) {
      var clipboardData = $e.clipboardData;
      if (clipboardData) {
        var items = clipboardData.items;
        if (!items) return;
        var types = clipboardData.types || [];
        var item = null;
        for (var i = 0; i < types.length; i++) {
          if (types[i] === "Files") {
            item = items[i];
            break;
          }
        }
        if (item && item.kind === "file") {
          // prevent filename being pasted parallel along
          // with the image pasting process
          stopEvent($e);
          var oFile = item.getAsFile();
          this.$refs.toolbar_left.$imgFilesAdd([oFile]);
        }
      }
    },
    $imgTouch(file) {
      var $vm = this;
      // TODO 跳转到图片位置
    },
    $imgDel(file) {
      this.markdownIt.image_del(file[1]);
      // 删除所有markdown中的图片
      let fileReg = file[0];
      let reg = new RegExp(`\\!\\[${file[1]._name}\\]\\(${fileReg}\\)`, "g");

      this.d_value = this.d_value.replace(reg, "");
      this.iRender();
      this.$emit("imgDel", file);
    },
    $imgAdd(pos, $file, isinsert) {
      if (isinsert === undefined) isinsert = true;
      var $vm = this;
      if (this.__rFilter == null) {
        // this.__rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
        this.__rFilter = /^image\//i;
      }
      this.__oFReader = new FileReader();
      this.__oFReader.onload = function(oFREvent) {
        $vm.markdownIt.image_add(pos, oFREvent.target.result);
        $file.miniurl = oFREvent.target.result;
        if (isinsert === true) {
          // 去除特殊字符
          $file._name = $file.name.replace(
            /[\[\]\(\)\+\{\}&\|\\\*^%$#@\-]/g,
            ""
          );

          $vm.insertText($vm.getTextareaDom(), {
            prefix: "![" + $file._name + "](" + pos + ")",
            subfix: "",
            str: ""
          });
          $vm.$nextTick(function() {
            $vm.$emit("imgAdd", pos, $file);
          });
        }
      };
      if ($file) {
        var oFile = $file;
        if (this.__rFilter.test(oFile.type)) {
          this.__oFReader.readAsDataURL(oFile);
        }
      }
    },
    $imgUpdateByUrl(pos, url) {
      var $vm = this;
      this.markdownIt.image_add(pos, url);
      this.$nextTick(function() {
        $vm.d_render = this.markdownIt.render(this.d_value);
      });
    },
    $img2Url(fileIndex, url) {
      var reg_str =
        "/(!\\[[^\\[]*?\\](?=\\())\\(\\s*(" + fileIndex + ")\\s*\\)/g";
      var reg = eval(reg_str);
      this.d_value = this.d_value.replace(reg, "$1(" + url + ")");
      this.$refs.toolbar_left.$changeUrl(fileIndex, url);
      this.iRender();
    },
    $imglst2Url(imglst) {
      if (imglst instanceof Array) {
        for (var i = 0; i < imglst.length; i++) {
          this.$img2Url(imglst[i][0], imglst[i][1]);
        }
      }
    },
    toolbar_left_click(_type) {
      toolbar_left_click(_type, this);
    },
    toolbar_left_addlink(_type, text, link) {
      toolbar_left_addlink(_type, text, link, this);
    },
    toolbar_right_click(_type) {
      toolbar_right_click(_type, this);
    },
    getNavigation($vm, full) {
      return getNavigation($vm, full);
    },
    // @event
    // 修改数据触发 （val ， val_render）
    change(val, render) {
      this.$emit("change", val, render);
    },
    // 切换全屏触发 （status , val）
    fullscreen(status, val) {
      this.$emit("fullScreen", status, val);
    },
    // 打开阅读模式触发（status , val）
    readmodel(status, val) {
      this.$emit("readModel", status, val);
    },
    // 切换阅读编辑触发 （status , val）
    previewtoggle(status, val) {
      this.$emit("previewToggle", status, val);
    },
    // 切换分栏触发 （status , val）
    subfieldtoggle(status, val) {
      this.$emit("subfieldToggle", status, val);
    },
    // 切换htmlcode触发 （status , val）
    htmlcode(status, val) {
      this.$emit("htmlCode", status, val);
    },
    // 监听ctrl + s
    save(val, render) {
      this.$emit("save", val, render);
    },
    // 导航栏切换
    navigationtoggle(status, val) {
      this.$emit("navigationToggle", status, val);
    },
    $toolbar_right_read_change_status() {
      this.s_readmodel = !this.s_readmodel;
      if (this.readmodel) {
        this.readmodel(this.s_readmodel, this.d_value);
      }
      if (this.s_readmodel && this.toolbars.navigation) {
        this.getNavigation(this, true);
      }
    },
    // ---------------------------------------
    // 滚动条联动
    $v_edit_scroll($event) {
      scrollLink($event, this);
    },
    // 获取textarea dom节点
    getTextareaDom() {
      return this.$refs.vNoteTextarea.$refs.vTextarea;
    },
    // 工具栏插入内容
    insertText(obj, { prefix, subfix, str, type }) {
      // if (this.s_preview_switch) {

      insertTextAtCaret(obj, { prefix, subfix, str, type }, this);
    },
    insertTab() {
      insertTab(this, this.tabSize);
    },
    insertOl() {
      insertOl(this);
    },
    removeLine() {
      removeLine(this);
    },
    insertUl() {
      insertUl(this);
    },
    unInsertTab() {
      unInsertTab(this, this.tabSize);
    },
    insertEnter(event) {
      insertEnter(this, event);
    },
    saveHistory() {
      this.d_history.splice(this.d_history_index + 1, this.d_history.length);
      this.d_history.push(this.d_value);
      this.d_history_index = this.d_history.length - 1;
    },
    // 编辑开关
    editableTextarea() {
      let text_dom = this.$refs.vNoteTextarea.$refs.vTextarea;
      if (this.editable) {
        text_dom.removeAttribute("disabled");
      } else {
        text_dom.setAttribute("disabled", "disabled");
      }
    },
    codeStyleChange(val, isInit) {
      isInit = isInit ? isInit : false;
      if (typeof this.p_external_link.hljs_css !== "function") {
        if (this.p_external_link.hljs_css != false) {
          console.error(
            "external_link.hljs_css is not a function, if you want to disabled this error log, set external_link.hljs_css to function or false"
          );
        }
        return;
      }
      var url = this.p_external_link.hljs_css(val);
      if (url.length === 0 && isInit) {
        console.warn(
          "hljs color scheme",
          val,
          "do not exist, loading default github"
        );
        url = this.p_external_link.hljs_css("github");
      }
      if (url.length > 0) {
        loadLink(url);
      } else {
        console.warn(
          "hljs color scheme",
          val,
          "do not exist, hljs color scheme will not change"
        );
      }
    },
    iRender(toggleChange) {
      var $vm = this;
      this.$render($vm.d_value, function(res) {
        // render
        $vm.d_render = res;
        // change回调  toggleChange == false 时候触发change回调
        if (!toggleChange) {
          if ($vm.change) $vm.change($vm.d_value, $vm.d_render);
        }
        // 改变标题导航
        if ($vm.s_navigation) getNavigation($vm, false);
        // v-model 语法糖
        $vm.$emit("input", $vm.d_value);
        // 塞入编辑记录数组
        if ($vm.d_value === $vm.d_history[$vm.d_history_index]) return;
        window.clearTimeout($vm.currentTimeout);
        $vm.currentTimeout = setTimeout(() => {
          $vm.saveHistory();
        }, 500);
      });
    },
    // 清空上一步 下一步缓存
    $emptyHistory() {
      this.d_history = [this.d_value]; // 编辑记录
      this.d_history_index = 0; // 编辑记录索引
    }
  },
  watch: {
    d_value: function(val, oldVal) {
      this.iRender();
    },
    value: function(val, oldVal) {
      if (val !== this.d_value) {
        this.d_value = val;
      }
    },
    subfield: function(val, oldVal) {
      this.s_subfield = val;
    },
    d_history_index() {
      if (this.d_history_index > 20) {
        this.d_history.shift();
        this.d_history_index = this.d_history_index - 1;
      }
      this.d_value = this.d_history[this.d_history_index];
    },
    editable: function() {
      this.editableTextarea();
    },
    defaultOpen: function(val) {
      let default_open_ = val;
      if (!default_open_) {
        default_open_ = this.subfield ? "preview" : "edit";
      }
      return (this.s_preview_switch =
        default_open_ === "preview" ? true : false);
    },
    codeStyle: function(val) {
      this.codeStyleChange(val);
    }
  },
  components: {
    "v-autoTextarea": autoTextarea,
    "v-md-toolbar-left": md_toolbar_left,
    "v-md-toolbar-right": md_toolbar_right
  }
};
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import 'lib/css/scroll.styl';
@import 'lib/css/halo-editor.styl';
</style>
<style lang="css" scoped>
.auto-textarea-wrapper {
  height: 100%;
}
</style>
